// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;

namespace SnapObjects.Data
{
    internal static class SqlBuilderExtensions
    {
        public static string ToSqlString(this SqlOperator sqlOperator)
        {
            switch (sqlOperator)
            {
                case SqlOperator.Between:
                {
                    return " BETWEEN {0} AND {1} ";
                }
                case SqlOperator.NotBetween:
                {
                    return " NOT BETWEEN {0} AND {1} ";
                }
                case SqlOperator.In:
                {
                    return " IN({0}) ";
                }
                case SqlOperator.NotIn:
                {
                    return " NOT IN({0}) ";
                }
                case SqlOperator.Equals:
                {
                    return " = ";
                }
                case SqlOperator.GreaterThan:
                {
                    return " > ";
                }
                case SqlOperator.GreaterThanOrEquals:
                {
                    return " >= ";
                }
                case SqlOperator.LessThan:
                {
                    return " < ";
                }
                case SqlOperator.LessThanOrEquals:
                {
                    return " <= ";
                }
                case SqlOperator.Like:
                {
                    return " LIKE ";
                }
                case SqlOperator.NotEquals:
                {
                    return " <> ";
                }
                case SqlOperator.NotLike:
                {
                    return " NOT LIKE ";
                }
                case SqlOperator.IsNot:
                {
                    return " IS NOT ";
                }
                case SqlOperator.Is:
                {
                    return " IS ";
                }
                case SqlOperator.Exists:
                {
                    return " EXISTS ";
                }
                case SqlOperator.NotExists:
                {
                    return "NOT EXISTS ";
                }
                case SqlOperator.EqualsAll:
                {
                    return " =ALL ";
                }
                case SqlOperator.NotEqualsAll:
                {
                    return " <>ALL ";
                }
                case SqlOperator.GreaterThanAll:
                {
                    return " >ALL ";
                }
                case SqlOperator.GreaterThanOrEqualsAll:
                {
                    return " >=ALL ";
                }
                case SqlOperator.LessThanAll:
                {
                    return " <ALL ";
                }
                case SqlOperator.LessThanOrEqualsAll:
                {
                    return " <=ALL ";
                }
                case SqlOperator.EqualsAny:
                {
                    return " =ANY ";
                }
                case SqlOperator.NotEqualsAny:
                {
                    return " <>ANY ";
                }
                case SqlOperator.GreaterThanAny:
                {
                    return " >ANY ";
                }
                case SqlOperator.GreaterThanOrEqualsAny:
                {
                    return " >=ANY ";
                }
                case SqlOperator.LessThanAny:
                {
                    return " <ANY ";
                }
                case SqlOperator.LessThanOrEqualsAny:
                {
                    return " <=ANY ";
                }
                default:
                {
                    throw new InvalidCastException(sqlOperator.ToString());
                }
            }
        }

        public static SqlOperator ToSqlOperator(this string text)
        {
            text = text.Trim();

            if (text.IndexOf('>') >= 0 ||
                text.IndexOf('<') >= 0 ||
                text.IndexOf('=') >= 0 ||
                text.IndexOf('!') >= 0)
            {
                text = text.Replace(" ", "");
            }

            if (text.Equals("=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Equals;
            }
            else if (text.Equals("!=", StringComparison.OrdinalIgnoreCase)
                || text.Equals("<>", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotEquals;
            }
            else if (text.Equals("<", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThan;
            }
            else if (text.Equals("<=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanOrEquals;
            }
            else if (text.Equals(">", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThan;
            }
            else if (text.Equals(">=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanOrEquals;
            }
            else if (text.Equals("like", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Like;
            }
            else if (text.Equals("not like", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotLike;
            }
            else if (text.Equals("in", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.In;
            }
            else if (text.Equals("not in", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotIn;
            }
            else if (text.Equals("between", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Between;
            }
            else if (text.Equals("not between", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotBetween;
            }
            else if (text.Equals("is", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Is;
            }
            else if (text.Equals("is not", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.IsNot;
            }
            else if (text.Equals("exists", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Exists;
            }
            else if (text.Equals("not exists", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotExists;
            }
            else if (text.Equals("=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.EqualsAll;
            }
            else if (text.Equals("<>all", StringComparison.OrdinalIgnoreCase)
                  || text.Equals("!=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotEqualsAll;
            }
            else if (text.Equals(">all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanAll;
            }
            else if (text.Equals(">=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanOrEqualsAll;
            }
            else if (text.Equals("<all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanAll;
            }
            else if (text.Equals("<=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanOrEqualsAll;
            }
            else if (text.Equals("=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.EqualsAny;
            }
            else if (text.Equals("<>any", StringComparison.OrdinalIgnoreCase)
                  || text.Equals("!=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotEqualsAny;
            }
            else if (text.Equals(">any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanAny;
            }
            else if (text.Equals(">=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanOrEqualsAny;
            }
            else if (text.Equals("<any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanAny;
            }
            else if (text.Equals("<=any", StringComparison.Ordinal))
            {
                return SqlOperator.LessThanOrEqualsAny;
            }

            throw new InvalidOperationException(text + " is not a valid SqlOperator.");
        }

        public static SqlBinaryOperator ToSqlBinaryOperator(this string text)
        {
            text = text.Trim();

            if (text.Equals("=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.Equals;
            }
            else if (text.Equals("!=", StringComparison.OrdinalIgnoreCase)
                || text.Equals("<>", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.NotEquals;
            }
            else if (text.Equals("<", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.LessThan;
            }
            else if (text.Equals("<=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.LessThanOrEquals;
            }
            else if (text.Equals(">", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.GreaterThan;
            }
            else if (text.Equals(">=", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.GreaterThanOrEquals;
            }
            else if (text.Equals("like", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.Like;
            }
            else if (text.Equals("not like", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.NotLike;
            }
            else if (text.Equals("in", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.In;
            }
            else if (text.Equals("not in", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.NotIn;
            }
            else if (text.Equals("is", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.Is;
            }
            else if (text.Equals("is not", StringComparison.OrdinalIgnoreCase))
            {
                return SqlBinaryOperator.IsNot;
            }
            /*else if (text.Equals("exists", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.Exists;
            }
            else if (text.Equals("not exists", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotExists;
            }
            else if (text.Equals("=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.EqualsAll;
            }
            else if (text.Equals("<>all", StringComparison.OrdinalIgnoreCase)
                  || text.Equals("!=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotEqualsAll;
            }
            else if (text.Equals(">all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanAll;
            }
            else if (text.Equals(">=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanOrEqualsAll;
            }
            else if (text.Equals("<all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanAll;
            }
            else if (text.Equals("<=all", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanOrEqualsAll;
            }
            else if (text.Equals("=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.EqualsAny;
            }
            else if (text.Equals("<>any", StringComparison.OrdinalIgnoreCase)
                  || text.Equals("!=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.NotEqualsAny;
            }
            else if (text.Equals(">any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanAny;
            }
            else if (text.Equals(">=any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.GreaterThanOrEqualsAny;
            }
            else if (text.Equals("<any", StringComparison.OrdinalIgnoreCase))
            {
                return SqlOperator.LessThanAny;
            }
            else if (text.Equals("<=any", StringComparison.Ordinal))
            {
                return SqlOperator.LessThanOrEqualsAny;
            }*/

            throw new InvalidOperationException(text + " is not a valid SqlBinaryOperator.");
        }

        private static readonly IList<SqlOperator> SqlOperators = new List<SqlOperator>() {
                SqlOperator.Between,
                SqlOperator.NotBetween,
                SqlOperator.Equals,
                SqlOperator.GreaterThan,
                SqlOperator.GreaterThanOrEquals,
                SqlOperator.LessThan,
                SqlOperator.LessThanOrEquals,
                SqlOperator.Like,
                SqlOperator.NotLike,
                SqlOperator.NotEquals,
                SqlOperator.IsNot,
                SqlOperator.Is
            };

        public static bool CanOperatorNullValue(this SqlOperator sqlOperator)
        {
            return SqlOperators.Contains(sqlOperator);
        }
    }
}
